#include "ff_utils.h"
#include "ff_utils_ogl.h"

using namespace std;
using namespace feifei;
using namespace glm;

E_ffState RtnState;
int ErrorCnt = 0;
void ChkRtn()
{
    if (RtnState != E_ffState::SUCCESS)
        ErrorCnt++;
}

float vertices[] = 
{
    /* position            Normal               texture coordinate */
    -0.5f, -0.5f, -0.5f,   0.0f,  0.0f, -1.0f,  0.0f, 0.0f,
     0.5f, -0.5f, -0.5f,   0.0f,  0.0f, -1.0f,  1.0f, 0.0f,
     0.5f,  0.5f, -0.5f,   0.0f,  0.0f, -1.0f,  1.0f, 1.0f,
     0.5f,  0.5f, -0.5f,   0.0f,  0.0f, -1.0f,  1.0f, 1.0f,
    -0.5f,  0.5f, -0.5f,   0.0f,  0.0f, -1.0f,  0.0f, 1.0f,
    -0.5f, -0.5f, -0.5f,   0.0f,  0.0f, -1.0f,  0.0f, 0.0f,

    -0.5f, -0.5f,  0.5f,   0.0f,  0.0f, 1.0f,   0.0f, 0.0f,
     0.5f, -0.5f,  0.5f,   0.0f,  0.0f, 1.0f,   1.0f, 0.0f,
     0.5f,  0.5f,  0.5f,   0.0f,  0.0f, 1.0f,   1.0f, 1.0f,
     0.5f,  0.5f,  0.5f,   0.0f,  0.0f, 1.0f,   1.0f, 1.0f,
    -0.5f,  0.5f,  0.5f,   0.0f,  0.0f, 1.0f,   0.0f, 1.0f,
    -0.5f, -0.5f,  0.5f,   0.0f,  0.0f, 1.0f,   0.0f, 0.0f,

    -0.5f,  0.5f,  0.5f,  -1.0f,  0.0f,  0.0f,  1.0f, 0.0f,
    -0.5f,  0.5f, -0.5f,  -1.0f,  0.0f,  0.0f,  1.0f, 1.0f,
    -0.5f, -0.5f, -0.5f,  -1.0f,  0.0f,  0.0f,  0.0f, 1.0f,
    -0.5f, -0.5f, -0.5f,  -1.0f,  0.0f,  0.0f,  0.0f, 1.0f,
    -0.5f, -0.5f,  0.5f,  -1.0f,  0.0f,  0.0f,  0.0f, 0.0f,
    -0.5f,  0.5f,  0.5f,  -1.0f,  0.0f,  0.0f,  1.0f, 0.0f,

     0.5f,  0.5f,  0.5f,   1.0f,  0.0f,  0.0f,  1.0f, 0.0f,
     0.5f,  0.5f, -0.5f,   1.0f,  0.0f,  0.0f,  1.0f, 1.0f,
     0.5f, -0.5f, -0.5f,   1.0f,  0.0f,  0.0f,  0.0f, 1.0f,
     0.5f, -0.5f, -0.5f,   1.0f,  0.0f,  0.0f,  0.0f, 1.0f,
     0.5f, -0.5f,  0.5f,   1.0f,  0.0f,  0.0f,  0.0f, 0.0f,
     0.5f,  0.5f,  0.5f,   1.0f,  0.0f,  0.0f,  1.0f, 0.0f,

    -0.5f, -0.5f, -0.5f,   0.0f, -1.0f,  0.0f,  0.0f, 1.0f,
     0.5f, -0.5f, -0.5f,   0.0f, -1.0f,  0.0f,  1.0f, 1.0f,
     0.5f, -0.5f,  0.5f,   0.0f, -1.0f,  0.0f,  1.0f, 0.0f,
     0.5f, -0.5f,  0.5f,   0.0f, -1.0f,  0.0f,  1.0f, 0.0f,
    -0.5f, -0.5f,  0.5f,   0.0f, -1.0f,  0.0f,  0.0f, 0.0f,
    -0.5f, -0.5f, -0.5f,   0.0f, -1.0f,  0.0f,  0.0f, 1.0f,

    -0.5f,  0.5f, -0.5f,   0.0f,  1.0f,  0.0f,  0.0f, 1.0f,
     0.5f,  0.5f, -0.5f,   0.0f,  1.0f,  0.0f,  1.0f, 1.0f,
     0.5f,  0.5f,  0.5f,   0.0f,  1.0f,  0.0f,  1.0f, 0.0f,
     0.5f,  0.5f,  0.5f,   0.0f,  1.0f,  0.0f,  1.0f, 0.0f,
    -0.5f,  0.5f,  0.5f,   0.0f,  1.0f,  0.0f,  0.0f, 0.0f,
    -0.5f,  0.5f, -0.5f,   0.0f,  1.0f,  0.0f,  0.0f, 1.0f
};
void BuildBox()
{
    OGlHandle* gl = OGlHandle::GetOglHandle();
    // 4. build shader
    Shader* shader_box = new Shader();
    {
        string vs = string(TEST_WORK_SPACE) + DIR_SPT + "shader" + DIR_SPT + "vs.vert";
        string fs = string(TEST_WORK_SPACE) + DIR_SPT + "shader" + DIR_SPT + "fs.frag";

        shader_box->BuildShader(vs.c_str(), fs.c_str());
        gl->AddShader("box", shader_box);

    }
    // 5. setup model
    Model* model_box = new Model();
    {
        gl->AddModel("box", model_box);

        // 5.2 bind camera
        model_box->BindCamera("default");

        // 5.3 create mesh
        Mesh* mesh_box = model_box->CreateMesh();
        {
            // 5.3.1 load vertices
            mesh_box->AddVertices(vertices, 36);
            // 5.3.2 load texture
            string tex = string(TEST_WORK_SPACE) + DIR_SPT + "texture" + DIR_SPT + "container.jpg";
            RtnState = mesh_box->AddTexture(tex, "texSampler"); ChkRtn();
            // 5.3.3 set polygon mode
            mesh_box->PolygonMode = GL_TRIANGLES;
            // 5.3.4 bind shader 
            mesh_box->BindShader("box");
        }
        model_box->EnShowCoor = true;
    }
}


void MouseCursor(double xpos, double ypos)
{
    OGlHandle* gl = OGlHandle::GetOglHandle();

    Model* model = gl->GetModel("box");
    Camera* camera = gl->GetCamera("default");

    if (IsHoldCtrl())
        model->OnMouseMove(xpos, ypos);
    else
        camera->OnMouseMove(xpos, ypos);
}
void MouseScroll(double xoffset, double yoffset)
{
    OGlHandle* gl = OGlHandle::GetOglHandle();

    Model* model = gl->GetModel("box");
    Camera* camera = gl->GetCamera("default");

    if (IsHoldCtrl())
        model->OnMouseScroll(yoffset);
    else
        camera->OnMouseScroll(yoffset);
}
void MouseButton(int button, int action, int mods)
{
    OGlHandle* gl = OGlHandle::GetOglHandle();
}
void KeyButton(int key, int scancode, int action, int mods)
{
    OGlHandle* gl = OGlHandle::GetOglHandle();
}

void UpdatePerDraw()
{
    OGlHandle* gl = OGlHandle::GetOglHandle();

    gl->SetCamera("default");

    // run for 5 seconds
    //if (tv > 5) gl->isQuite = true; 
}


int main()
{
    LOG("ogl test.\n");

    OGlHandle* gl = OGlHandle::GetOglHandle();

    // 1. init opengl
    RtnState = gl->Init();     ChkRtn();
    // 2. create window
    RtnState = gl->window.CreateGlfwWindow("ogl test", 768, 512);     ChkRtn();
    {
        gl->AddCursorPosCallback(MouseCursor);
        gl->AddScrollCallback(MouseScroll);
        gl->AddMouseButtonCallback(MouseButton);
        gl->AddKeyBoardCallback(KeyButton);
    }

    // 3. init camera
    Camera* camera = new Camera();
    {
        camera->Reset(gl->window.Width, gl->window.Height);
        gl->AddCamera("default", camera);
        gl->SetCamera("default");
    }
    // 4. build shader
    Shader* shader = new Shader();
    {
        string vs = string(TEST_WORK_SPACE) + DIR_SPT + "shader" + DIR_SPT + "vs.vert";
        string fs = string(TEST_WORK_SPACE) + DIR_SPT + "shader" + DIR_SPT + "fs.frag";

        shader->BuildShader(vs.c_str(), fs.c_str());
        gl->AddShader("box", shader);

    }
    // 5. setup model
    Model* model = new Model();
    {
        gl->AddModel("box", model);

        // 5.2 bind camera
        model->BindCamera("default");

        // 5.3 create mesh
        Mesh* mesh = model->CreateMesh();
        {
            // 5.3.1 load vertices
            mesh->AddVertices(vertices, 36);
            // 5.3.2 load texture
            string tex = string(TEST_WORK_SPACE) + DIR_SPT + "texture" + DIR_SPT + "container.jpg";
            RtnState = mesh->AddTexture(tex, "texSampler"); ChkRtn();
            // 5.3.3 set polygon mode
            mesh->PolygonMode = GL_TRIANGLES;
            // 5.3.4 bind shader 
            mesh->BindShader("box");
        }
        model->EnShowCoor = true;
    }

    // 6. hookup pre-draw function
    gl->AddUpdatePerDrawCallback(UpdatePerDraw);

    // enter main loop
    gl->Run();

    // release
    gl->Release();
    
	return ErrorCnt;
}
